package cn.sylinx.horm.core;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.UUID;

import cn.sylinx.horm.config.specific.SpecificConfigHolder;
import cn.sylinx.horm.core.common.PreparedCallWrapper;
import cn.sylinx.horm.core.common.PreparedCallable;
import cn.sylinx.horm.core.stat.SqlStatEventHelper;

/**
 * 执行包装
 * 
 * @author johnhan
 *
 */
public class DefaultPreparedCallWrapper implements PreparedCallWrapper {

    @Override
    public <T> PreparedCallable<T> wrap(PreparedCallable<T> preparedCallable) {
        return new StatPreparedCallable<T>(preparedCallable);
    }

    static class StatPreparedCallable<T> implements PreparedCallable<T> {

        private final PreparedCallable<T> preparedCallable;

        StatPreparedCallable(PreparedCallable<T> preparedCallable) {
            this.preparedCallable = preparedCallable;
        }

        public String parseStatSql(String sql, Object[] params) {
            return sql + "; --> params:" + parseParams(params);
        }

        private String parseParams(Object[] params) {
            if (params == null || params.length == 0) {
                return "[]";
            }

            StringBuilder sb = new StringBuilder();
            sb.append("[");

            for (Object param : params) {
                if (param != null) {
                    sb.append(param);
                } else {
                    sb.append("NULL");
                }
                sb.append(",");
            }
            sb.deleteCharAt(sb.length() - 1);
            sb.append("]");

            return sb.toString();
        }

        @Override
        public T call(String datasourceName, Connection connection, String sqlInput, Object[] params)
                throws SQLException {

            if (!SpecificConfigHolder.isSqlStatOpen(datasourceName)) {
                return preparedCallable.call(datasourceName, connection, sqlInput, params);
            }

            // 启用了统计
            Throwable error = null;
            String statSql = parseStatSql(sqlInput, params);
            String seq = UUID.randomUUID().toString();
            long b = System.currentTimeMillis();
            SqlStatEventHelper.sendSqlStatBefore(seq, datasourceName, statSql, b);

            try {
                return preparedCallable.call(datasourceName, connection, sqlInput, params);
            } catch (Exception e) {
                error = e;
                throw e;
            } finally {
                SqlStatEventHelper.sendSqlStatAfter(seq, datasourceName, statSql, System.currentTimeMillis() - b,
                        error);
            }
        }
    }
}
